package com.gaga.console.base.utils;

import cn.hutool.core.io.FileUtil;
import com.gaga.common.constant.BvConstants;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @Description 压缩文件处理 @Author xcc@winning.com.cn @Copyright 卫宁健康科技集团股份有限公司 @Date 2020/9/21 13:28
 */
public class ZipFileUtil {

    public static final Logger logger = LoggerFactory.getLogger(ZipFileUtil.class);

    /**
     * 解压zip文件到制定路径
     *
     * @param zipFile
     * @param descDir
     * @throws IOException
     */
    public static void zipToFile(File zipFile, String descDir) throws IOException {
        File pathFile = new File(descDir);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
        for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {
            ZipEntry entry = entries.nextElement();
            String zipEntryName = entry.getName();
            InputStream in = zip.getInputStream(entry);
            String outPath = (descDir + zipEntryName).replaceAll("\\*", "/");
            File file = new File(outPath.substring(0, outPath.lastIndexOf("/")));
            if (!file.exists()) {
                file.mkdirs();
            }

            if (new File(outPath).isDirectory()) {
                continue;
            }

            OutputStream out = new FileOutputStream(outPath);
            byte[] buf1 = new byte[1024];
            int len;
            while ((len = in.read(buf1)) > 0) {
                out.write(buf1, 0, len);
            }
            in.close();
            out.close();
        }
        zip.close();

        // 解压完成之后，对于文件检索一下，如果不是图片类型的直接删除掉，返回出现问题
//        List<File> filesList = FileUtil.loopFiles(descDir);
//        filesList.forEach(itemFile -> {
//            String fileName = itemFile.getName();
//            String fileExtName = getFileExtName(fileName);
//            if (StringUtils.isNotBlank(fileExtName) && !Arrays.asList(BvConstants.FILE_SUFFIX_WHITE_ARR).contains(fileExtName)) {
//                FileUtil.del(itemFile.getPath());
//            }
//        });

    }

    public static Map<String, String> readZipFileToMap(File zipFile) throws IOException {
        String[] incluedFileTypeArr = new String[]{".txt"};
        return readZipFileToMap(zipFile, incluedFileTypeArr);
    }

    public static Map<String, String> readZipFileToMap(File zipFile, String[] incluedFileTypeArr) throws IOException {
        Map<String, String> fileMaps = new HashMap<>();

        ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
        for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {
            StringBuilder stringBuilder = new StringBuilder(1000);
            ZipEntry entry = entries.nextElement();
            String zipEntryName = entry.getName();
            //文件夹直接过滤掉
            if (entry.isDirectory()) {
                continue;
            }
            //过滤掉不需要的文件类型
            String isExist = Arrays.stream(incluedFileTypeArr).filter(zipEntryName::endsWith).findAny().orElse(null);
            if (isExist == null) {
                continue;
            }
            InputStream in = zip.getInputStream(entry);
            BufferedReader bf = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            String len;
            while ((len = bf.readLine()) != null) {
                stringBuilder.append(len);
            }
            in.close();
            fileMaps.put(zipEntryName, stringBuilder.toString());
        }
        zip.close();
        return fileMaps;
    }

    public static Map<String, String> readZipFileToMapWithWrap(File zipFile) throws IOException {
        String[] incluedFileTypeArr = new String[]{".txt",".TXT"};
        Map<String, String> fileMaps = new HashMap<>();

        ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
        for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {
            StringBuilder stringBuilder = new StringBuilder(1000);
            ZipEntry entry = entries.nextElement();
            String zipEntryName = entry.getName();
            if (entry.isDirectory()) {
                continue;
            }
            String isExist = Arrays.stream(incluedFileTypeArr).filter(zipEntryName::endsWith).findAny().orElse(null);
            if (isExist == null) {
                //视频文件跳过，后面需要保存视频路径
                fileMaps.put(zipEntryName, "");
                continue;
            }
            InputStream in = zip.getInputStream(entry);
            BufferedReader bf = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            String line;
            while ((line = bf.readLine()) != null) {
                stringBuilder.append(line).append('\n'); // 添加换行符
            }
            in.close();
            // 移除最后多余的空行（可选）
            if (stringBuilder.length() > 0 && stringBuilder.charAt(stringBuilder.length() - 1) == '\n') {
                stringBuilder.setLength(stringBuilder.length() - 1);
            }
            fileMaps.put(zipEntryName, stringBuilder.toString());
        }
        zip.close();
        return fileMaps;
    }

    /**
     * 导出zip文件，将sourceFilePath目录打包
     *
     * @param response
     * @param sourceFilePath
     */
    public static void exportZip(HttpServletResponse response, String sourceFilePath) {
        // 文件名以时间戳作为前缀
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String filePrefix = sdf.format(new Date());
        String downloadName = filePrefix + ".zip";
        exportZip(response, sourceFilePath, downloadName);
    }

    /**
     * 导出zip文件，将sourceFilePath目录打包
     *
     * @param response
     * @param sourceFilePath
     */
    public static void exportZip(HttpServletResponse response, String sourceFilePath, String downloadName) {
        try {
            byte[] data = createZip(sourceFilePath);
            exportZipByData(response, data, downloadName);
        } catch (Exception e) {
            logger.error("打包错误：{}", sourceFilePath, e);
        }
    }


    public static void exportZipByData(HttpServletResponse response, byte[] data, String downloadName) {
        // 将文件进行打包下载
        try (OutputStream out = response.getOutputStream()) {
            // 接收压缩包字节
            response.reset();
            response.addHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Expose-Headers", "*");
            response.setContentType("application/octet-stream;charset=UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=\"" + URLEncoder.encode(downloadName, "UTF-8") + "\"");
            response.addHeader("Content-Length", "" + data.length);
            IOUtils.write(data, out);
            out.flush();
        } catch (Exception e) {
            logger.error("打包错误：{}", e);
        }
    }

    public static byte[] createZip(String sourceFilePath) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        // 将目标文件打包成zip导出
        File file = new File(sourceFilePath);
        handlerFile(zip, file, "");
        IOUtils.closeQuietly(zip);
        return outputStream.toByteArray();
    }

    public static void handlerFile(ZipOutputStream zip, File file, String dir) throws Exception {
        Set<String> addedEntries = new HashSet<>();
        handlerFileForSingleFile(zip, file, addedEntries, null, dir);
    }


    public static void handlerFileForSingleFile(ZipOutputStream zip, File file, Set<String> addedEntries, File singleFile, String dir) throws Exception {
        // 如果当前的是文件夹，则进行进一步处理
        if (dir.startsWith("\\")) {
            dir = dir.replaceFirst("\\\\", "");
        }

        if (file.isDirectory()) {
            // 得到文件列表信息
            File[] fileArray = file.listFiles();
            if (fileArray == null) {
                return;
            }
            String entryName = dir + "/";
            if (!addedEntries.contains(entryName)) {
                // 将文件夹添加到下一级打包目录
                zip.putNextEntry(new ZipEntry(entryName));
                addedEntries.add(entryName);
            }
            dir = dir.length() == 0 ? "" : entryName;
            // 递归将文件夹中的文件打包
            for (File f : fileArray) {
                handlerFileForSingleFile(zip, f, addedEntries, singleFile, dir + f.getName());
            }
        } else {
            if (singleFile != null && !file.equals(singleFile)) {
                return;
            }
            // 当前的是文件，打包处理
            // 文件输入流
            if (!addedEntries.contains(dir)) {
                ZipEntry entry = new ZipEntry(dir);
                zip.putNextEntry(entry);
                zip.write(FileUtils.readFileToByteArray(file));
                addedEntries.add(dir);
                zip.flush();
                zip.closeEntry();
            }
        }
    }


    public static String getFileExtName(String fileName) {
        String[] splitName = fileName.split("\\.");
        return splitName[splitName.length - 1];
    }
}
